﻿using System;
using System.Security.Principal;
using NCommet.Core.Services;
using System.Configuration;
using System.Collections.Generic;

namespace NCommet.Core.Agents
{
    /// <summary>
    /// AccessLevel is a flags (bitfield) enumeration of the possible access levels
    /// that can be assigned on an item.
    /// </summary>
    [Flags]
    public enum AccessLevel
    {
        /// <summary>
        /// Denotes denial of access level.
        /// </summary>
        None = 0,
        /// <summary>
        /// Grants view access level. This is required on Item.Get factory method.
        /// </summary>
        View = 1,
        /// <summary>
        /// Grants edit access level. This is required on Item.Save method and on setting the Item.Content property.
        /// </summary>
        Edit = 2,
        /// <summary>
        /// Grants delete access level. This is required on Item.Delete method, for the item being deleted.
        /// </summary>
        Delete = 4,
        /// <summary>
        /// Grants detach access level. This is required on Item.ChangeParent method, for the item being detached.
        /// </summary>
        Detach = 8,
        /// <summary>
        /// Grants add child access level. This is required on ItemCollection.Add and ItemCollection.Insert methods and on Item.ChangeParent method for the new candidate parent.
        /// </summary>
        AddChild = 16,
        /// <summary>
        /// A combination of all the possible access levels
        /// </summary>
        Everything = View | Edit | Delete | Detach | AddChild
    }

    /// <summary>
    /// IAuthorizationManager handles role based authorization on items.
    /// </summary>
    public interface IAuthorizationManager
    {
        /// <summary>
        /// Checks if the specified role has explicit access rights on the given item.
        /// </summary>
        /// <param name="item">The given <see cref="NCommet.Core.Item" /></param>
        /// <param name="role">The specified role.</param>
        /// <returns>True, if the <paramref name="role"/> has explicit access rights to the <paramref name="item"/>.</returns>
        bool IsAccessLevelSet(Item item, string role);

        /// <summary>
        /// Gets the access level that the specified principal has on the given item.
        /// </summary>
        /// <param name="item">The given <see cref="NCommet.Core.Item" /></param>
        /// <param name="principal">The specified principal.</param>
        /// <returns>The <see cref="NCommet.Core.Agents.AccessLevel" /> that the <paramref name="principal"/> has on the <paramref name="item"/>.</returns>
        AccessLevel GetAccessLevel(Item item, IPrincipal principal);

        /// <summary>
        /// Gets the access level that the specified role has on the given item.
        /// </summary>
        /// <param name="item">The given <see cref="NCommet.Core.Item" /></param>
        /// <param name="role">The specified role.</param>
        /// <returns>The <see cref="NCommet.Core.Agents.AccessLevel" /> that the <paramref name="role"/> has on the <paramref name="item"/>.</returns>
        AccessLevel GetAccessLevel(Item item, string role);

        /// <summary>
        /// Explicitly assigns perimissions for the specified role on the given item.
        /// </summary>
        /// <param name="item">The given <see cref="NCommet.Core.Item" /></param>
        /// <param name="role">The specified role.</param>
        /// <param name="accessLevel">The <see cref="NCommet.Core.Agents.AccessLevel" /> that is assigned for the <paramref name="role"/> on the <paramref name="item"/>.</param>
        void SetAccessLevel(Item item, string role, AccessLevel accessLevel);

        /// <summary>
        /// Removes all explicitly assigned permissions that the specified role has on the given item.
        /// </summary>
        /// <param name="item">The given <see cref="NCommet.Core.Item" /></param>
        /// <param name="role">The specified role.</param>
        void ResetAccessLevel(Item item, string role);

        /// <summary>
        /// Filters the children of the given item, returning only those items on which
        /// the given principal has the required permissions.
        /// </summary>
        /// <param name="parent">The parent item.</param>
        /// <param name="principal">The specified principal.</param>
        /// <param name="requiredAccessLevel">The required <see cref="NCommet.Core.Agents.AccessLevel" />.</param>
        /// <returns>A list of <see cref="NCommet.Core.Item"/>.</returns>        
        IList<Item> FilterChildren(Item parent, IPrincipal principal, AccessLevel requiredAccessLevel);

        /// <summary>
        /// Checks if the current logged-in user has the specified permissions on the given item.
        /// </summary>
        /// <param name="item">The given <see cref="NCommet.Core.Item" /></param>
        /// <param name="accessLevelRequired">The required <see cref="NCommet.Core.Agents.AccessLevel" />.</param>
        /// <returns>True, if the logged-in user has the required access level on the <paramref name="item"/></returns>
        bool HasAccess(Item item, AccessLevel accessLevelRequired);

        /// <summary>
        /// The role name used for the anonymous (not logged-in) role.
        /// Please note that logged-in roles should at least have the permissions of the not logged-in role.
        /// </summary>
        string AnonymousRoleName { get; set; }

        /// <summary>
        /// Informs the authorization manager that the specified roles have been deleted from the roles system.
        /// </summary>
        /// <param name="roles">The specified roles.</param>
        void RolesDeleted(string[] roles);
    }


}
